﻿using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;

namespace Willow.MVC.Result
{

    /// <summary>
    /// 描述：导出Excel的Result
    /// </summary>
    public class ExportExcelResult : ActionResult
    {
        /// <summary>
        /// 导出Excel的Result
        /// </summary>
        /// <param name="data">数据</param>
        public ExportExcelResult(IEnumerable<Object> data)
            : this(data, "")
        {
            DateTime time = DateTime.Now;
            this.FileName = string.Format("{0}_{1}_{2}_{3}",
                time.Month, time.Day, time.Hour, time.Minute);
        }

        /// <summary>
        /// 导出Excel的Result
        /// </summary>
        /// <param name="data">数据</param>
        /// <param name="fileName">文件名</param>
        public ExportExcelResult(IEnumerable<Object> data, string fileName)
            : this(data, fileName, null)
        {
            this.TitleFormater = p => p;
        }

        /// <summary>
        /// 导出Excel的Result
        /// </summary>
        /// <param name="data">数据</param>
        /// <param name="fileName">文件名</param>
        /// <param name="titleFormater">标题格式化</param>
        public ExportExcelResult(IEnumerable<Object> data, string fileName, Func<string, string> titleFormater)
        {
            this.Data = data;
            this.FileName = fileName;
            this.TitleFormater = titleFormater;
        }

        /// <summary>
        /// 数据
        /// </summary>
        public IEnumerable<Object> Data
        {
            get;
            set;
        }

        /// <summary>
        /// 文件名
        /// </summary>
        public string FileName
        {
            get;
            set;
        }

        /// <summary>
        /// 标题格式化
        /// </summary>
        public Func<string, string> TitleFormater
        {
            get;
            set;
        }

        public override void ExecuteResult(ControllerContext context)
        {
            if (Data == null)
            {
                new EmptyResult().ExecuteResult(context);
                return;
            }

            SetResponse(context);
        }

        /// <summary>
        /// 描述：设置并向客户端发送请求响应
        /// 创建人：Mark
        /// 创建时间：2013-08-31
        /// </summary>
        /// <param name="context">The context.</param>
        private void SetResponse(ControllerContext context)
        {

            FileName = HttpUtility.UrlEncode(Encoding.UTF8.GetBytes(FileName));

            MemoryStream ms = ConvertToExcel();

            context.HttpContext.Response.Clear();
            context.HttpContext.Response.ClearContent();
            context.HttpContext.Response.Buffer = true;
            context.HttpContext.Response.Charset = "GB2312";
            context.HttpContext.Response.ContentEncoding = Encoding.UTF8;
            context.HttpContext.Response.ContentType = "application/ms-excel";
            context.HttpContext.Response.AddHeader("Content-Disposition", "attachment; filename=" + FileName + ".xls");
            context.HttpContext.Response.AddHeader("Content-Length", ms.Length.ToString());
            context.HttpContext.Response.BinaryWrite(ms.ToArray());
            context.HttpContext.Response.End();
        }

        /// <summary>
        /// 描述：把泛型集合转换成Excel表格
        /// </summary>
        /// <returns></returns>
        private MemoryStream ConvertToExcel()
        {
            var ms = new MemoryStream();
            IWorkbook workbook = new HSSFWorkbook();
            ISheet sheet = workbook.CreateSheet("sheet1");
            AddTableHead(sheet);
            AddTableBody(sheet);
            workbook.Write(ms);
            ms.Flush();
            ms.Position = 0;
            return ms;
        }

        /// <summary>
        /// 描述：添加Excel数据。
        /// 创建人：Mark
        /// 创建时间：2013-08-31
        /// </summary>
        /// <param name="sheet">The sheet.</param>
        private void AddTableBody(ISheet sheet)
        {
            if (Data == null || !this.Data.Any())
            {
                return;
            }

            PropertyDescriptorCollection properties = FindProperties();

            if (properties.Count <= 0)
            {
                return;
            }

            int itemIndex = 0;
            foreach (var item in Data)
            {
                IRow row = sheet.CreateRow(itemIndex + 1);//在工作表中添加一行
                for (int j = 0; j < properties.Count; j++)
                {

                    object obj = properties[j].GetValue(item);
                    obj = obj == null ? string.Empty : obj.ToString();
                    ICell cell = row.CreateCell(j);//在行中添加一列
                    cell.SetCellValue(obj.ToString());//设置列的内容
                }
                itemIndex++;
            }
        }

        /// <summary>
        /// 描述：添加Excel表头。
        /// 创建人：Mark
        /// 创建时间：2013-08-31
        /// </summary>
        /// <param name="sheet">The sheet.</param>
        private void AddTableHead(ISheet sheet)
        {
            PropertyDescriptorCollection properties = FindProperties();

            if (properties.Count <= 0)
            {
                return;
            }

            IRow row = sheet.CreateRow(0);//在工作表中添加一行
            for (int i = 0; i < properties.Count; i++)
            {
                ICell cell = row.CreateCell(i);//在行中添加一列

                string value = properties[i].Name;

                value = TitleFormater(value);

                cell.SetCellValue(value);//设置列的内容
                cell.CellStyle = GetHeadStyle(sheet.Workbook);
            }
        }

        /// <summary>
        /// 描述：获取表头样式
        /// </summary>
        /// <param name="workbook">The workbook.</param>
        /// <returns></returns>
        private ICellStyle GetHeadStyle(IWorkbook workbook)
        {
            ICellStyle style = workbook.CreateCellStyle();
            //新建一个字体样式对象
            IFont font = workbook.CreateFont();
            //设置字体加粗样式
            font.Boldweight = short.MaxValue;
            //使用SetFont方法将字体样式添加到单元格样式中 
            style.SetFont(font);
            return style;
        }

        /// <summary>
        /// 返回属性集合。
        /// </summary>
        /// <returns></returns>
        private PropertyDescriptorCollection FindProperties()
        {
            return TypeDescriptor.GetProperties(Data.FirstOrDefault());
        }

    }
}
